home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Prog / B-C / C++ FAQ Reference 1.0 / C++ FAQ Reference 1.0.rsrc / TEXT_1728.txt < prev    next >
Encoding:
Text File  |  1993-06-30  |  2.9 KB  |  13 lines

  1. I'll use a 'inserting into a linked list' as a prototypical example.  The obvious approach is to allow insertion at the head and tail of the list, but that would produce a library that is too weak (a weak library is almost worse than no library).  Whenever encapsulation frustrates rather than helps a user, it may be that the class' public interface needs enhancing.  If class List only supports adding at the front and tail, it *definitely* needs more strength.
  2.  
  3. This answer will be a lot to swallow for novice C++'ers, so I'll give a couple of options.  As usual, the first is easiest, while the second option is better. I also give a thumbnail sketch of a third option, which has certain advantages and disadvantages over the second option.
  4.  
  5. [1] Empower the List with a 'viewport' or 'cursor' that references an arbitrary list element.  Implies adding member fns to List such as advance(), backup(), atend(), atbegin(), rewind(), fastforward(), and current().  'current()' returns the element of the List that is currently 'under the cursor'.  Finally you'll need to add a few more member fns to *mutate* the list, such as changeto(X), insert(X), remove(), etc.
  6.  
  7. [2] Provide a separate class called ListIter.  ListIter has member fns named similar to the above (though probably with operator overloading, but that's just syntactic sugar for member fns).  The List itself would have none of the above mentioned member fns, and the ListIter would be a 'friend' of List (ListIter would have to have access to the innards of List; this allows the world to have safe access abilities to List without violating encapsulation).
  8.  
  9. The reason option [2] is better becomes apparent when you use classes that only support [1].  In particular, if you pass a List off to a subcall, you'd better hope the subcall didn't warp the 'cursor' around, or your code may fail.  Also, if you try to get all pairs of elements, it's very hard if you only have one cursor.  The distinct-class iterator concept removes these restrictions.  My own class library uses these extensively, as will most any other commercial grade class library.
  10.  
  11. Note that the options are not mutually exclusive; it is possible to provide both [2] *and* [1], giving rise to the notion of a 'primary' list position, with instances of ListIter being somewhat secondary.
  12.  
  13. [3] The third possibility considers the entire iteration as an atomic event.  A class is created which embodies this event.  The nice thing about this third alternative is that the public access methods (which may be virtual fns) can be avoided during the inner loop, thus enhancing performance.  The down side is that you get extra object code in the application, since templates gain speed by duplicating code.  This third technique is due to Andrew Koenig in a paper published recently in JOOP ['Templates as interfaces', JOOP, 4, 5 (Sept 91)]. You can also see a taste of it in Bjarne Stroustrup's book, The C++ Programming Language Second Edition (look for 'Comparator' in the index).